package com.kisyou.JDBC使用;
/**
 * 进程的执行结果 := 程序代码 + 进程执行时的环境
 *
 * 同样的代码，不同的环境是可能得到不同的结果的，所以如果遇到了运行结果不符合预期，除了检查代码的问题之外，现在应该把更多精力放到检查周边环境是否符合预期上了。
 */

import com.mysql.cj.jdbc.MysqlDataSource;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

/**
 * 如何使用 JDBC 连接数据库
 * 1. DataSource（数据源）
 * 2. Connection（连接）
 * 3. Statement（SQL 语句）/ PreparedStatement
 * 4. ResultSet（结果集）
 * 对比打电话的例子：
 * DataSource 类比 联系方式 or 通讯录
 * Connection 类比打通电话，需要 DataSource 作为前提
 * Statement：客户向服务器发送的 SQL 语句
 * ResultSet：服务器向客户回的结果
 */
public class SetUpDataSourceTest {
    // 数据库的相关信息
    // 1. 数据库所在的主机：127.0.0.1 / localhost
    // 2. 数据库所在的端口：3306 / 3307 ...
    // 3. 数据库的用户名: ...
    // 4. 数据库的密码: ...
    // 5. 额外的配置选项:
        // 5.1.  连接使用的字符集编码 characterEncoding=utf8
        // 5.2.  不使用加密连接: useSSL=false
        // 5.3.  指定时区: serverTimezone=Asia/Shanghai
    public static void main1(String[] args) throws SQLException {

        // 第一种创建方式
        /**
        MysqlDataSource dataSource = new MysqlDataSource();

        dataSource.setServerName("127.0.0.1");
        dataSource.setPort(3307);
        dataSource.setUser("debian-sys-maint");
        dataSource.setPassword("co7lI761pHOFy9gx");
        dataSource.setDatabaseName("jdbc_mysql");
        dataSource.setCharacterEncoding("utf8");
        dataSource.setUseSSL(false);//不使用加密连接
        dataSource.setServerTimezone("Asia/Shanghai");//指定时区是亚洲上海（东八）
         */

        //第二种创建方式
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUser("debian-sys-maint");
        dataSource.setPassword("co7lI761pHOFy9gx");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3307/jdbc_mysql?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai");

        //从 DataSource 对象中得到 Connection 对象
        /*
        //写法一: 在此时，之所以没有报异常是因为在这之前，我就已经把异常抛出去了
        Connection connection = dataSource.getConnection();//类比拨通电话
        //走到这一步就可以使用con对象了
        connection.close();//类比挂电话

        //如果此时并没有将异常抛出去该如何处理呢？
        Connection connection = null;
        try{
            connection = dataSource.getConnection();//类比拨通电话
            //走到这一步就可以使用con对象了
        }catch(SQLException exc){
            //处理异常
        }finally{
            if(connection != null){
                try{
                    con.close();
                }catch(SQLException exc){
                    //处理异常
                }
            }
        }
         */

        //写法二:
        // try-with-resource
        // 利用这种写法，不用自己写 con.close()，代码结构看起来干净
        try(Connection connection = dataSource.getConnection()){
            // 利用 con 对象执行 SQL
        }catch(SQLException exc){
            // 处理异常
        }

    }

    //创建 Statement 对象
    //从 ResultSet 中遍历每行结果，从每行中获取每列的值
    public static void main2(String[] args) throws SQLException {
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUser("debian-sys-maint");
        dataSource.setPassword("co7lI761pHOFy9gx");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3307/jdbc_mysql?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai");

        try(Connection connection = dataSource.getConnection()){
            // 利用 con 对象执行 SQL

            // -- 列出当前所在库的所有表名称
            String sql = "show tables";

            /**
             * 创建 Statement 对象
             */
            try(PreparedStatement preparedStatement = connection.prepareStatement(sql)){
                // execute: 执行
                // query: 查询
                try(ResultSet resultSet = preparedStatement.executeQuery()){
                    //结果就可以从 ResultSet 对象中获取

                    /**
                     * 从 ResultSet 中遍历每行结果，从每行中获取每列的值
                     */
                    //此时的 next() 相当于之前 hasNext() + next()
                    while(resultSet.next()){
                        //resultSet 代表当前遍历的行
                        // 第一列的结果是表的名称，所以是字符串 String
                        String tableName = resultSet.getString(1);    // 下标是 1
                        System.out.println(tableName);
                    }
                }
            }
        }
    }

    /**
     * 动态 SQL
     * @param args
     * @throws SQLException
     */
    // 静态 SQL
    //String sql = "show tables";
    //String sql = "select * from oj_records where oj_id = 1"
    //实际中，我们往往面临的是动态 SQL
    //暂时无法在飞书文档外展示此内容
    //PreparedStatement 通过占位符(placeholder)和动态绑定的方式做到
    public static void main(String[] args) throws SQLException {
        Scanner sc = new Scanner(System.in);

        String name = sc.nextLine();
        int chineseAc = sc.nextInt();
        int MathAc = sc.nextInt();


        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUser("debian-sys-maint");
        dataSource.setPassword("co7lI761pHOFy9gx");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3307/jdbc_mysql?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai");

        try (Connection connection = dataSource.getConnection()) {
            // 利用 con 对象执行 SQL

            // -- 列出当前所在库的所有表名称
            String sql = "select * from exam_result  where chinese > ? and math > ?  and name = ?";

            /**
             * 创建 Statement 对象
             */
            try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                /**
                 * 针对 PreparedStatement 执行动态绑定时
                 *
                 * int x = ...;
                 * ps.setInt(1, x);
                 *
                 * String s = "...";
                 * ps.setString(1, s);
                 *
                 * String datetime = "2023-04-24 20:54:00"
                 * ps.setString(1, datetime);
                 *
                 */
                preparedStatement.setString(3,name);//用名字替换第三个？
                System.out.println(preparedStatement);
                preparedStatement.setInt(1, chineseAc);//用语文成绩替换第一个？
                System.out.println(preparedStatement);
                preparedStatement.setInt(2,MathAc);//用数学成绩替换第二个？
                System.out.println(preparedStatement);

                // execute: 执行
                // query: 查询
                try (ResultSet resultSet = preparedStatement.executeQuery()) {
                    //结果就可以从 ResultSet 对象中获取

                    /**
                     * 从 ResultSet 中遍历每行结果，从每行中获取每列的值
                     *
                     * 关于 ResultSet 读取列
                     * 1）读取第 n 列
                     * rs.getInt(n);    // 读取第 n 列
                     *
                     * 2) 根据列名称读取
                     * rs.getInt("oj_id");
                     */

                     /* SQL语句执行
                     * 查询结果的执行
                     * select ...;
                     * show ...;
                     *
                     * ResultSet rs = ps.executeQuery();
                     */

                     /* 不带查询结果的执行
                     * create database ...;
                     * create table ...;
                     * drop database ...;
                     * drop table ...;
                     *
                     * insert into ...;
                     * update ...;
                     * delete ...;
                     *
                     * // number 本次执行成功多少行
                     * int number = ps.executeUpdate();
                     */
                    //此时的 next() 相当于之前 hasNext() + next()
                    while (resultSet.next()) {
                        //resultSet 代表当前遍历的行
                        /**
                         * 从 ResultSet 获取值时
                         * int x = rs.getInt(1);
                         * String s = rs.getString(1);
                         * String datetime = rs.getString(1);
                         */
                        String id = resultSet.getString(1);    // 下标是 1
                        String name1 = resultSet.getString(2);
                        int chinese = resultSet.getInt(3);
                        int math = resultSet.getInt(4);
                        int english = resultSet.getInt(5);
                        System.out.println(id + ' ' + name1 + ' ' + chinese + ' ' + math + ' ' + english);
                    }
                }
            }
        }
    }
}
